
// 词法分析器

#include <stdlib.h>
#include "input.h"
#include "lex.h"
#define LOG_TAG "Lexer"
#include "log.h"

#define IsDigit(c)         (c >= '0' && c <= '9')
#define IsOctDigit(c)      (c >= '0' && c <= '7')
#define IsHexDigit(c)      (IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
#define IsLetter(c)        ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_'))
#define IsLetterOrDigit(c) (IsLetter(c) || IsDigit(c))
#define ToUpper(c)           (c & ~0x20)
#define AddHex(v, c)       (v = (v << 4) + (IsDigit(c) ? (c - '0') : (ToUpper(c) - 'A' + 10)))

#define CURSOR  (Input.cursor)
#define    IS_EOF    ((Input.cursor-Input.base) >= Input.size)

typedef int (*Scanner)(void);

static Scanner  Scanners[0x100];
int             Token;
const char*     TokenStart;
int             TokenLen;
int             TokenLine;
int             TokenColumn;

// 标记的名称数组
// token.h:
//   TOKEN(TK_STRUCT, "struct")
//   TOKEN(TK_ID, "identifier")
//   TOKEN(TK_SEMICOLON, ";")
const char* TokenStrings[] = {
    "",
#define TOKEN(k, s) s,
  #include "token.h"
#undef  TOKEN
};

// 跳过空白字符及注释
static void SkipWhiteSpace(void)
{
    int ch = *CURSOR;
    // <TAB>-\t, <VT>-\v, <FF>-\f, <SP>- , <NBSP>不支持, <BOM>不支持, <USP>不支持
    // <LF>-\n, <CR>-\r, <LS>不支持, <PS>不支持
    while (ch == '\t' || ch == '\v' || ch == '\f' || ch == ' ' ||
           ch == '\r' || ch == '\n' || ch == '/') {
        switch (ch) {
        case '\n':
            Input.line++;
            Input.lineHead = ++CURSOR;
            break;

        case '/':    // 注释
            if (CURSOR[1] == '/') {
                // 单行注释
                CURSOR += 2;
                while (*CURSOR != '\n' && !IS_EOF) {
                    CURSOR++;
                }
            } else if (CURSOR[1] == '*') {
                // 多行注释
                CURSOR += 2;
                while (CURSOR[0] != '*' || CURSOR[1] != '/') {
                    if (*CURSOR == '\n') {
                        Input.line++;
                        Input.lineHead = ++CURSOR;
                        continue;
                    }
                    CURSOR++;
                    if (IS_EOF) {
                        Warn("Expect */");
                        return;
                    }
                }
                CURSOR += 2;
            } else {
                // 除号
                return;
            }
            break;

        default:
            CURSOR++;
            break;
        }
        ch = *CURSOR;
    }
}

// 区分标识符与关键字
static int FindKeyword(const char *str, int len)
{
    int i, j;
    for (i = TK_BEGIN; i < TK_ID; i++) {
        for (j = 0; j < len; j++) {
            if (TokenStrings[i][j] != str[j]) {
                break;
            }
        }
        if (j >= len && TokenStrings[i][j] == '\0') {
            break;
        }
    }
    return i;
}

// 解析标识符
static int ScanIdentifier(void)
{
    CURSOR++;
    while (IsLetterOrDigit(*CURSOR)) CURSOR++;
    return FindKeyword(TokenStart, (int) (CURSOR - TokenStart));
}

// 解析一个数
static int ScanNumericLiteral(void)
{
    if (*CURSOR == '+' || *CURSOR == '-') CURSOR++;
    if (*CURSOR == '0' && ToUpper(CURSOR[1]) == 'X') {  // hexical  0x123ABC
        CURSOR += 2;
        if (!IsHexDigit(*CURSOR)) {
            Error("Expect hex digit");
            exit(EXT_NotExpect);
        }
        while (IsHexDigit(*CURSOR)) CURSOR++;
        return TK_INTEGER;
    } else { // decimal    123456789
        CURSOR++;
        while (IsDigit(*CURSOR)) CURSOR++;
        if (*CURSOR == '.') {
            CURSOR++;
            while (IsDigit(*CURSOR)) CURSOR++;
            return TK_FLOAT;
        } else if (*CURSOR == 'e' && *CURSOR == 'E') {
            CURSOR++;
            if (*CURSOR == '+' || *CURSOR == '-') CURSOR++;
            while (IsDigit(*CURSOR)) CURSOR++;
            return TK_FLOAT;
        } else {
            return TK_INTEGER;
        }
    }
}

#define SINGLE_CHAR_SCANNER(t)  \
static int Scan##t(void) {      \
    CURSOR++;                   \
    return TK_##t;              \
}

SINGLE_CHAR_SCANNER(COMMA)      // ,
SINGLE_CHAR_SCANNER(COLON)      // :
SINGLE_CHAR_SCANNER(LPAREN)     // (
SINGLE_CHAR_SCANNER(RPAREN)     // )
SINGLE_CHAR_SCANNER(LBRACKET)   // [
SINGLE_CHAR_SCANNER(RBRACKET)   // ]
SINGLE_CHAR_SCANNER(LBRACE)     // {
SINGLE_CHAR_SCANNER(RBRACE)     // }
SINGLE_CHAR_SCANNER(SEMICOLON)  // ;

// 解析非法字符
static int ScanBadChar(void)
{
    Error("illegal character:\\x%x", (unsigned char) *CURSOR);
    CURSOR++;
    NextToken();
    return Token;
}

// 解析小括号
void ScanParen(void)
{
    if (Token != TK_LPAREN) {
        Error("Expect %s", TokenStrings[TK_LPAREN]);
        exit(EXT_NotExpect);
    }

    TokenStart = CURSOR;
    TokenLine = Input.line;
    TokenColumn = CURSOR - Input.lineHead;
    Token = TK_PAREN;

    int level = 1;
    while (level != 0 && !IS_EOF) {
        if (*CURSOR == '(') {
            level++;
        } else if (*CURSOR == ')') {
            level--;
        } else if (*CURSOR == '\n') {
            Input.line++;
            Input.lineHead = CURSOR + 1;
        }
        CURSOR++;
    }

    TokenLen = (int) (CURSOR - TokenStart) - 1;
    if (IS_EOF) {
        Error("Expect %s", TokenStrings[TK_RPAREN]);
        exit(EXT_NotExpect);
    }
}

// 解析大括号
void ScanBrace(void)
{
    if (Token != TK_LBRACE) {
        Error("Expect %s", TokenStrings[TK_LBRACE]);
        exit(EXT_NotExpect);
    }

    TokenStart = CURSOR;
    TokenLine = Input.line;
    TokenColumn = CURSOR - Input.lineHead;
    Token = TK_BRACE;

    int level = 1;
    while (level != 0 && !IS_EOF) {
        if (*CURSOR == '{') {
            level++;
        } else if (*CURSOR == '}') {
            level--;
        } else if (*CURSOR == '\n') {
            Input.line++;
            Input.lineHead = CURSOR + 1;
        }
        CURSOR++;
    }

    TokenLen = (int) (CURSOR - TokenStart) - 1;
    if (IS_EOF) {
        Error("Expect %s", TokenStrings[TK_RBRACE]);
        exit(EXT_NotExpect);
    }
}

void InitLexer(void)
{
    int i;
    for (i = 0; i < 0x100; i++) {
        if (IsLetter(i)) {  // [a-z A-Z _  $]
            Scanners[i] = ScanIdentifier;
        } else if (IsDigit(i)) {
            Scanners[i] = ScanNumericLiteral;
        } else {
            Scanners[i] = ScanBadChar;
        }
    }

    Scanners['+']  = ScanNumericLiteral;
    Scanners['-']  = ScanNumericLiteral;
    Scanners['.']  = ScanNumericLiteral;
    // see Macro SINGLE_CHAR_SCANNER(t)
    Scanners[',']  = ScanCOMMA;
    Scanners[':']  = ScanCOLON;
    Scanners['(']  = ScanLPAREN;
    Scanners[')']  = ScanRPAREN;
    Scanners['[']  = ScanLBRACKET;
    Scanners[']']  = ScanRBRACKET;
    Scanners['{']  = ScanLBRACE;
    Scanners['}']  = ScanRBRACE;
    Scanners[';']  = ScanSEMICOLON;
}

void NextToken(void)
{
    SkipWhiteSpace();

    TokenStart = CURSOR;
    TokenLine = Input.line;
    TokenColumn = CURSOR - Input.lineHead;
    if (IS_EOF) {
        Token = TK_END;
        TokenLen = 0;
        return;
    }
    Token = Scanners[(unsigned char) *CURSOR]();
    TokenLen = (int) (CURSOR - TokenStart);
}

/**
 * Expect current token to be tk. If so, get next token; otherwise,
 * report error
 */
void Expect(int tk)
{
    if (Token == tk) {
        NextToken();
        return;
    }
    Error("Expect %s", TokenStrings[tk]);
    exit(EXT_NotExpect);
}
